#pragma once
#include <iostream>
#include <vector>
#include <pthread.h>
#include <semaphore.h>

const static int defaultcap = 5;
template <class T>
class RingQueue
{
public:
    void P(sem_t & sem)
    {
        sem_wait(&sem);
    }
    void V(sem_t & sem)
    {
        sem_post(&sem);
    }
    RingQueue(int cap = defaultcap) : cap_(cap),rq_(cap), c_index_(0), p_index_(0)
    {
        sem_init(&cdata_sem, 0, 0);
        sem_init(&pspace_sem, 0, 5);

        pthread_mutex_init(&c_mutex_, nullptr);
        pthread_mutex_init(&p_mutex_, nullptr);
    }
    ~RingQueue()
    {
        sem_destroy(&cdata_sem);
        sem_destroy(&pspace_sem);

        pthread_mutex_destroy(&c_mutex_);
        pthread_mutex_destroy(&p_mutex_);
    }
    void Push(const T& in)
    {
        //先获取信号量，再加锁，确保获取锁之前已经确保了资源的可用性
        P(pspace_sem);
        pthread_mutex_lock(&p_mutex_);
        rq_[p_index_] = in;
        p_index_++;
        p_index_ %= cap_;
        pthread_mutex_unlock(&p_mutex_);
        V(cdata_sem);
    }
    T Pop()
    {
        P(cdata_sem);
        pthread_mutex_lock(&c_mutex_);
        T t = rq_[c_index_];
        c_index_++;
        c_index_ %= cap_;
        pthread_mutex_unlock(&c_mutex_);
        V(pspace_sem);
        return t;
    }

private:
    // 使用数组实现环形队列
    std::vector<T> rq_;
    int cap_;
    // 两个指针指向当前的位置
    int p_index_;
    int c_index_;
    // 两个信号量
    sem_t cdata_sem;
    sem_t pspace_sem;

    // 两个互斥锁
    pthread_mutex_t c_mutex_;
    pthread_mutex_t p_mutex_;
};